<?php

declare(strict_types=1);

namespace App\CustHub\Service;

use Carbon\Carbon;

class DateService
{
    /**
     * 计算下次待处理的时间
     *
     * @param array $setting 配置参数 ['send_type' => 'day|week|month', 'time' => 'H:i', 'num' => '1,3,5'|array]
     * @param int|null $stopTime linux时间戳 停止日期
     * @return int|false 下次执行时间戳，如果没有下次执行时间则返回false
     */
    public static function calculateNextSendTime(array $setting, ?int $stopTime = null)
    {
        // 设置一个很大的时间戳
        $tempTime = strtotime('2222-12-30 23:59');

        $send_type = $setting['send_type'] ?? '';
        $time = $setting['send_time'] ?? '';
        $num = $setting['num'] ?? [];

        // 将字符串形式的num转换为数组
        if (is_string($num)) {
            $num = explode(',', $num);
        }

        if ($send_type == 2) {
            if (date('H:i') >= $time) { // 过了今日时间点，则记为明天为第一次执行
                $nextTime = strtotime(date('Y-m-d ') . $time) + 24 * 3600;
            } else {
                $nextTime = strtotime(date('Y-m-d ') . $time);
            }
        } elseif ($send_type == 3) {
            if (empty($num)) {
                return false;
            }

            foreach ($num as $v) {
                if ((date('w') == $v || (date('w') == 0 && $v == 7))
                    && date('H:i') < $time
                ) { // 当天，且还未开始，则全部下个日期
                    $nextTime = strtotime(date('Y-m-d ') . $time);
                } else {
                    $weekArray = [
                        'next monday',
                        'next tuesday',
                        'next wednesday',
                        'next thursday',
                        'next friday',
                        'next saturday',
                        'next sunday'
                    ];
                    $nextTime = strtotime(
                        date('Y-m-d ', strtotime($weekArray[$v - 1])) . ' ' . $time
                    );
                }
                if ($nextTime < $tempTime) {
                    $tempTime = $nextTime;
                }
            }
            $nextTime = $tempTime;
        } elseif ($send_type == 4) {
            if (empty($num)) {
                return false;
            }

            foreach ($num as $v) {
                $nextTime = strtotime(date("Y-m-{$v} ") . $time);
                if ($nextTime <= time()) {
                    $netTime = self::nextMonthToday(date("Y-m-{$v} ") . $time);
                    $nextTime = strtotime($netTime . $time);
                }
                if ($nextTime < $tempTime) {
                    $tempTime = $nextTime;
                }
            }

            $nextTime = $tempTime;
        } else {
            $nextTime = strtotime($time);
            if ($nextTime < time()) {
                return false;
            }
        }

        // 截止日期
        if ($stopTime && $nextTime >= $stopTime) {
            return false;
        }

        return $nextTime;
    }

    /**
     * 获取下个月的今天
     *
     * @param string $date 日期字符串
     * @return string
     */
    public static function nextMonthToday(string $date): string
    {
        // 获取今天是一个月中的第多少天
        $currentMonthT = date('t', strtotime($date));
        $currentMonthD = date('d', strtotime($date));
        $currentMonthM = date('m', strtotime($date));

        // 获取下个月最后一天及下个月的总天数
        $nextMonthEnd = self::getNextMonthEndDate($date);
        $nextMonthT = date('t', strtotime($nextMonthEnd));

        $returnDate = '';
        if ($currentMonthD == $currentMonthT) { // 月末
            // 获取下个月的月末
            $returnDate = $nextMonthEnd;
        } else { // 非月末
            // 获取下个月的今天
            if ($currentMonthD > $nextMonthT) { // 如 01-30，二月没有今天,直接返回2月最后一天
                $returnDate = $nextMonthEnd;
            } else {
                $returnDate = date('Y-m', strtotime($nextMonthEnd)) . '-' . $currentMonthD;
            }
        }
        return $returnDate;
    }

    /**
     * 获取下个月最后一天
     *
     * @param string $date 日期字符串
     * @return string
     */
    public static function getNextMonthEndDate(string $date): string
    {
        $firstDay = date('Y-m-01', strtotime($date));
        $lastDay = date('Y-m-d', strtotime("$firstDay +2 month -1 day"));
        return $lastDay;
    }
}